package com.dhcc.sds.standard.service.impl;

import com.baomidou.mybatisplus.plugins.Page;
import com.dhcc.core.framework.base.service.impl.BaseServiceImpl;
import com.dhcc.core.framework.util.CommonUtil;
import com.dhcc.core.framework.util.DateUtil;
import com.dhcc.sds.standard.dao.SdsStandRuleBaseMapper;
import com.dhcc.sds.standard.dao.SdsStandRuleCalMapper;
import com.dhcc.sds.standard.dao.SdsStandSourceMapper;
import com.dhcc.sds.standard.entity.SdsStandRuleBaseCalEntity;
import com.dhcc.sds.standard.entity.SdsStandRuleBaseEntity;
import com.dhcc.sds.standard.entity.SdsStandSourceEntity;
import com.dhcc.sds.standard.function.GetRuleValueSrv;
import com.dhcc.sds.standard.service.IsdsStandRuleCalService;

import com.googlecode.aviator.AviatorEvaluator;
import org.apache.commons.jexl2.Expression;
import org.apache.commons.jexl2.JexlContext;
import org.apache.commons.jexl2.JexlEngine;
import org.apache.commons.jexl2.MapContext;
import org.apache.commons.lang.StringEscapeUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Service("sdsStandRuleCalService")
public class SdsStandRuleCalServiceImpl extends BaseServiceImpl<SdsStandRuleCalMapper, SdsStandRuleBaseCalEntity> implements IsdsStandRuleCalService {

    @Resource
    private SdsStandRuleBaseMapper sdsStandRuleBaseMapper;
    @Resource
    private SdsStandSourceMapper sdsStandSourceMapper;

    @Override
    public List<SdsStandRuleBaseCalEntity> page(Page<SdsStandRuleBaseCalEntity> page, Map<String, Object> params) {
        List<SdsStandRuleBaseCalEntity> result = this.baseMapper.page(page, params);
        for (SdsStandRuleBaseCalEntity ruleBaseCal : result){
            String s = StringEscapeUtils.unescapeHtml(ruleBaseCal.getCalculate());
            ruleBaseCal.setCalculate(s);
        }
        return result;
    }

    @Override
    public Object handleRuleExpressions(String matchRule, Long episodeId,String orderSql) {
        Map<String,Object> resMap=new HashMap<>();
        List<String> ruleCodeList=new ArrayList<>();
        String p1 = "\\(.*?\\)";
        if (CommonUtil.isEmpty(matchRule)) {
            resMap.put("ruleCodeList",ruleCodeList);
            resMap.put("bool",false);
            return resMap;
        }
        String expreStrBak = matchRule;
        // 查找规则公式小括号以内的规则代码
        Pattern p = Pattern.compile(p1);
        Matcher m = p.matcher(matchRule);
        // 遍历找到的所有括号
        while (m.find()) {
            String ruleCode = m.group().substring(1, m.group().length() - 1);//ruleCode=281  ruleCode=681 此处分开查询
            String ruleVal = ruleParse(ruleCode, episodeId,orderSql);//表示ruleCode对应的true/false
            if("true".equals(ruleVal)){
                ruleCodeList.add(ruleCode);
            }
            // 如果规则值是unknown的，代表不是正常返回，这时表达式的“默认值”应具体判断
            if ("unknown".equals(ruleVal)) {
                if (m.start() != 0 && expreStrBak.substring(m.start() - 1, m.start()).equals("!")) {
                    ruleVal = "true";
                } else {
                    ruleVal = "false";
                }
            }
            matchRule = matchRule.replace(m.group(), ruleVal);
        }
        // 将表达式中的大括号中括号替换为小括号，以及其他其他字符替换为可执行字符
        matchRule = matchRule.replace("{", "(").replace("}", ")");
        matchRule = matchRule.replace("[", "(").replace("]", ")");

        // 运行表达式结果且返回
        try {
            boolean execute = (boolean) AviatorEvaluator.execute(matchRule);
            resMap.put("ruleCodeList",ruleCodeList);
            resMap.put("bool",execute);
            return resMap;
        } catch (Exception e) {
            resMap.put("ruleCodeList",ruleCodeList);
            resMap.put("bool",false);
            return resMap;
        }
    }

    @Override
    public int calRuleResult(Long episodeId, SdsStandRuleBaseEntity sdsStandRuleBaseEntity) {
        int res = 0;
        if (StringUtils.isEmpty(sdsStandRuleBaseEntity)){
            return 0;
        }else {
            Integer isDefault = sdsStandRuleBaseEntity.getIsDefault();
            String calType = sdsStandRuleBaseEntity.getCalType();

            List<SdsStandRuleBaseCalEntity> ruleBaseCalEntities = this.baseMapper.selectByRuleIdAsc(sdsStandRuleBaseEntity.getId());
            if (null != ruleBaseCalEntities && ruleBaseCalEntities.size() > 0){
                if (1 ==  ruleBaseCalEntities.size()){
                    SdsStandRuleBaseCalEntity sdsStandRuleBaseCalEntity = ruleBaseCalEntities.get(0);
                    if (StringUtils.isEmpty(sdsStandRuleBaseCalEntity.getDatasource())){
                        return isDefault;
                    }else {
                        SdsStandSourceEntity source = sdsStandSourceMapper.selectById(sdsStandRuleBaseCalEntity.getDatasource());
                        SdsStandSourceEntity parentSourceEntity = sdsStandSourceMapper.selectById(source.getParentId());
                        String methodName = parentSourceEntity.getSourceCode();
                        try {
                            Class GetValueSrv = Class.forName("com.dhcc.sds.standard.function.GetRuleValueSrv");
                            GetRuleValueSrv function = (GetRuleValueSrv)GetValueSrv.newInstance();
                            Method method1 = GetValueSrv.getMethod(methodName, Long.class, Long.class, Integer.class, Long.class, Long.class);
                            String value = String.valueOf(method1.invoke(function, episodeId, sdsStandRuleBaseCalEntity.getDatasource(), sdsStandRuleBaseCalEntity.getCurrentTime(),
                                    sdsStandRuleBaseCalEntity.getDic(), sdsStandRuleBaseCalEntity.getValueTime()));

                        }catch (Exception e){
                            e.printStackTrace();
                            res = isDefault;
                        }
                    }
                }else {

                }
            }
        }
        return res;
    }

    public String ruleParse(String ruleCode, Long episodeId,String orderSql){
        String ruleVal = "unknown";
        // 通过ruleCode获取规则信息
        SdsStandRuleBaseEntity sdsStandRuleBaseEntity = new SdsStandRuleBaseEntity();
        sdsStandRuleBaseEntity.setRuleCode(ruleCode);
        sdsStandRuleBaseEntity = sdsStandRuleBaseMapper.selectOne(sdsStandRuleBaseEntity);
        if (sdsStandRuleBaseEntity == null) {
            return ruleVal;
        }
        // 取值为空时规则默认值
        int defaultValue = sdsStandRuleBaseEntity.getIsDefault();
        // 运算类型
        String ruleType = "";
        if (sdsStandRuleBaseEntity.getRuleType() != null) {
            ruleType = sdsStandRuleBaseEntity.getCalType();
        }
        String ruleExpreStr = "";
        List<SdsStandRuleBaseCalEntity> ruleBaseCalEntities = this.baseMapper.selectByRuleIdAsc(sdsStandRuleBaseEntity.getId());
        for (SdsStandRuleBaseCalEntity sdsStandRuleBaseCalEntity : ruleBaseCalEntities){
            String value = "";
            if (1 == sdsStandRuleBaseCalEntity.getCurrentTime()){
                //获取当前时间
                value = DateUtil.getTime();
            }else {
                SdsStandSourceEntity source = sdsStandSourceMapper.selectById(sdsStandRuleBaseCalEntity.getDatasource());
                SdsStandSourceEntity parentSourceEntity = sdsStandSourceMapper.selectById(source.getParentId());
                String methodName = parentSourceEntity.getSourceCode();
                try {
                    Class GetRuleValueSrv = Class.forName("com.dhcc.sds.standard.function.GetRuleValueSrv");
                    GetRuleValueSrv function = (GetRuleValueSrv) GetRuleValueSrv.newInstance();
                    Method method1 = GetRuleValueSrv.getMethod(methodName, Long.class, Long.class, Integer.class, Long.class, Long.class,String.class);
                    value = String.valueOf(method1.invoke(function, episodeId, sdsStandRuleBaseCalEntity.getDatasource(), sdsStandRuleBaseCalEntity.getCurrentTime(),
                            sdsStandRuleBaseCalEntity.getDic(), sdsStandRuleBaseCalEntity.getValueTime(),orderSql));
                    if (CommonUtil.isEmpty(value)) {
                        if (CommonUtil.isNotEmpty(defaultValue)) {
                            if (defaultValue == 1) {
                                ruleVal = "true";
                            } else {
                                ruleVal = "false";
                            }
                        }
                        return ruleVal;
                    }
                }catch (Exception e){
                    e.printStackTrace();
                    ruleVal = "unknown";
                }
            }
            value = modelRuleValue(value, ruleType);
            String operator = sdsStandRuleBaseCalEntity.getCalculate();
            if (operator.contains("\"")||operator.contains("\'")||operator.contains("‘")||operator.contains("“")) {
                operator = operator.replace("‘", "\'").replace("’", "\'");
                operator = operator.replace("“", "\"").replace("”", "\"");
                value = "\""+value+"\"";
            }
            ruleExpreStr = ruleExpreStr + value + operator;
        }
        // 运行表达式结果且返回
        if (!StringUtils.isEmpty(ruleExpreStr)){
            try {
                JexlEngine engine = new JexlEngine();
                JexlContext context = new MapContext();
                Expression expression = engine.createExpression(ruleExpreStr);
                ruleVal = expression.evaluate(context).toString();
            } catch (Exception e) {
                e.printStackTrace();
                return ruleVal;
            }
        }
        return ruleVal;
    }

    private String modelRuleValue(String bfVal, String ruleType) {
        String afVal = "";
        if (CommonUtil.isEmpty(bfVal)) {
            return afVal;
        }
        if(CommonUtil.isEmpty(ruleType)){
            afVal = bfVal;
            return afVal;
        }
        long divisor = 1;
        switch (ruleType) {
            case "Day":
                // 一天毫秒数
                divisor = 24 * 60 * 60 * 1000;
                afVal = String.valueOf(DateUtil.parse(bfVal).getTime() / divisor);
                break;
            case "Hour":
                // 1小时毫秒数
                divisor = 60 * 60 * 1000;
                afVal = String.valueOf(DateUtil.parse(bfVal).getTime() / divisor);
                break;
            case "Minute":
                // 一分钟毫秒数
                divisor = 60 * 1000;
                afVal = String.valueOf(DateUtil.parse(bfVal).getTime() / divisor);
                break;
            case "String":
                afVal = "\"" + bfVal + "\"";
                break;
            default:
                afVal = bfVal;
                break;
        }
        return afVal;
    }


}
